package djrelay_server;

import java.io.*;
import java.net.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;

/** A starting point for network servers. Instantiate
 *  it and call "listen" to start it up. You'll need to
 *  override handleConnection, but in many cases listen can
 *  remain unchanged. NetworkServer uses SocketUtil to simplify
 *  the creation of the PrintWriter and BufferedReader.
 *
 *  From <a href="http://courses.coreservlets.com/Course-Materials/">the
 *  coreservlets.com tutorials on servlets, JSP, Struts, JSF, Ajax, GWT, and Java</a>.
 */

public class NetworkServer extends Thread {
  private int port;
  private final ServerSocket listener;
  public final ExecutorService pool;
  public ConnectionHandler mConnectionHandle;


  /** Build a server on specified port. It will continue to
   *  accept connections, passing each to handleConnection until
   *  the server is killed (e.g., Control-C in the startup window)
   *  or System.exit() from handleConnection or elsewhere
   *  in the Java code).
   */

  public NetworkServer(int port, int poolSize) throws IOException {

    listener = new ServerSocket(port);
    pool = Executors.newFixedThreadPool(poolSize);
    Logger.getLogger(DJRelay_ServerFE.class.getName()).log(Level.INFO, "ServerSocket instance created");

  }

  /** Monitor a port for connections. Each time one is
   *  established, pass resulting Socket to handleConnection.
   */

  @Override
  public void run(){
      
      try {
          for(;;){
              pool.execute(mConnectionHandle = new ConnectionHandler(listener.accept()));
              Logger.getLogger(DJRelay_ServerFE.class.getName()).log(Level.INFO, "Are we stuck?");              
          }
      } catch (IOException ioe) {
          pool.shutdown();
          System.err.println("IOException: " + ioe);
      }
  }
  
  void shutdownAndAwaitTermination(ExecutorService pool) throws IOException {
      listener.close();
      pool.shutdown();  // Disable new tasks from being submitted
      try {
          // Wait a bit for existing tasks to terminate
          if (!pool.awaitTermination(60, TimeUnit.SECONDS)){
              pool.shutdownNow();  // Cancel currently executing tasks
              // Wait a while for tasks to respond to being cancelled
              if (!pool.awaitTermination(60, TimeUnit.SECONDS))
                System.err.println("Pool did not terminate");
          }
      } catch (InterruptedException ie) {
        // (Re-) Cancel if current thread also interrupted
        pool.shutdownNow();
        // Preserve interrupt status
        Thread.currentThread().interrupt();
      }
  }

  /** Gets port on which server is listening. */

  public int getPort() {
    return(port);
  }
}